package ca.cbc.panacea.elixir.entity;

import ca.cbc.panacea.elixir.util.ElixirProperties;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.io.Files;
import com.google.common.io.LineProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.*;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.*;

/**
 * @author : Arash Bizhanzadeh <arash.bizhanzadeh@cbc.ca>
 *         Date: 11-11-17
 *         Time: 11:15 AM
 *         CBC.ca All rights reserved.
 */

@Entity
@Access(AccessType.FIELD)
public class PanaceaInstance implements Serializable{
    private static final long serialVersionUID = 5736624797354165275L;
    private static Logger logger = LoggerFactory.getLogger(PanaceaInstance.class);
    public static final String PROPERTY_FILE_NAME = "panacea.properties";
    public static final Object TEMPLATE_DIR = "templates/";
    public static final String MAPPING_FILE = "mapping.xml";
    public static final String PUBLISHER_FILE = "publisher.xml";
    public static final String PROPERTY_DIR = "properties/";

    @Id
    private String directory;



    @Transient
    private PanaceaProperty properties;

    private String processId;
//    private static final String TEMP_DIR = "hotfolder/";
    @Transient
    private List<String> logFiles;
    @Transient
    private List<String> templatesFiles;

    @Transient String currentFileContent;

    @Transient
    private String currentFileName;
    //Panacea properties


    public PanaceaInstance() {
    }



    public String getDirectory() {

        return directory;
    }


    public void setDirectory(String directory) {
        logger.debug("setting directory to {}", directory);
        this.directory = directory;
    }



    public PanaceaProperty getProperties() {
        if(properties== null){
            //try to read from property file:
            String fileName = ElixirProperties.instance.getDirectoryFor(this) + PROPERTY_DIR +PROPERTY_FILE_NAME;
            final File propertyFile = new File(fileName);
            if (propertyFile.exists()) {
                LineProcessor<PanaceaProperty> processor =
                        new LineProcessor<PanaceaProperty>() {
                            PanaceaProperty property = new PanaceaProperty();
                            @Override
                            public boolean processLine(String s) throws IOException {
                                String[] str = s.split("=");
                                if (str.length == 2 && !str[0].trim().equals("") && !str[1].trim().equals("")) {
                                    if(str[0].trim().equals("ftp.base.url")){
                                        property.setFtpUrl(str[1].trim());
                                    }else if (str[0].trim().equals("ftp.username")){
                                        property.setFtpUsername(str[1].trim());
                                    }else if (str[0].trim().equals("ftp.password")){
                                        property.setFtpPassword(str[1].trim());
                                    } else if(str[0].trim().equals("new.file.handler.cron.expr")){
                                        property.setFetchCron(str[1].trim());
                                    }else if(str[0].trim().equals("publisher.one.cron.expr")){
                                        property.setPublisherCron1(str[1].trim());
                                    }else if(str[0].trim().equals("publisher.two.cron.expr")){
                                        property.setPublisherCron2(str[1].trim());
                                    }else if(str[0].trim().equals("publisher.three.cron.expr")){
                                        property.setPublisherCron3(str[1].trim());
                                    }else if(str[0].trim().equals("gsa.url")){
                                        property.setGsaUrl(str[1].trim());
                                    }else if(str[0].trim().equals("gsa.datasource")){
                                        property.setGsaDatasource(str[1].trim());
                                    }
                                    return true;
                                } else {
                                    return true;
                                }
                            }
                            @Override
                            public PanaceaProperty getResult() {
                                return property;
                            }
                        };

                try {
                    logger.debug("Reading properties from file {}", propertyFile.getCanonicalPath());
                    properties = Files.readLines(propertyFile, Charset.forName("UTF-8"), processor);
                } catch (IOException e) {
                    logger.error("Error reading property file", e);
                }
            }else{
                logger.debug("Creating new set of properties, property {} does not exist", fileName);
                properties = new PanaceaProperty();
            }
        }
        return properties;
    }

    public void setProperties(PanaceaProperty properties) {
        this.properties = properties;
    }

    public String getPropertyFileName() {
        return String.format("%s%s%s",ElixirProperties.instance.getDirectoryFor(this), PROPERTY_DIR , PROPERTY_FILE_NAME) ;
    }

    public String getTemplateDir(){
        return String.format("%s%s",ElixirProperties.instance.getDirectoryFor(this),TEMPLATE_DIR);
    }

    public String getMappingFile(){
        return String.format("%s%s", ElixirProperties.instance.getDirectoryFor(this), MAPPING_FILE);
    }

    public String getPublisherFile() {
        return String.format("%s%s", getRootDir(), PUBLISHER_FILE);
    }
    public String getOutputDir() {
        return String.format("%s%s", ElixirProperties.instance.getOutputDir() ,this.getDirectory() );
    }


    public String getDataDir() {
        return String.format("%s%s%s",
                ElixirProperties.instance.getLoggingDir(),directory, "/hotfolder" );
    }
    public String getRootDir() {
        return   String.format("%s%s%s%s",ElixirProperties.instance.getRootDir()
                    , "/", getDirectory(),'/');
    }
    public String getLoggingDir(){
        return String.format("%s%s%s", ElixirProperties.instance.getLoggingDir(),directory,'/');
    }


    public String getWorkDir(){
        return String.format("%s%s%s", ElixirProperties.instance.getLoggingDir(),directory , "/");
    }

    public String getDaemonErrorlog(){
        return String.format("%s%s%s", ElixirProperties.instance.getLoggingDir(),directory,"/instance.err");
    }

     public String getDaemonOutputlog() {
        return String.format("%s%s%s", ElixirProperties.instance.getLoggingDir(),directory,"/instance.out");
    }

    public String getDaemonPidFile() {
        return String.format("%s%s%s", ElixirProperties.instance.getLoggingDir(),directory,"/instance.pid");
    }

    public List<String> getLogFiles() {
        String[] files = new File(getLoggingDir()).list();
        return Arrays.asList(files);
    }

    public List<String> getTemplateFiles() {
        return Arrays.asList(new File(getTemplateDir()).list());
    }


    public void setCurrentFile(String fileName){
        currentFileName = fileName;
        try {
            if (fileName.equals("mapping.xml")) {
                logger.debug("Reading Mapping file");
                readFile(getMappingFile());
            } else if(fileName.equals("publisher.xml")){
                logger.debug("Reading publisher file");
                readFile(getPublisherFile());
            }else if(fileName.equals("panacea.properties")){
                logger.debug("Reading property file");
                readFile(getPropertyFileName());
            } else if(fileName.startsWith("template_")){
                logger.debug("Reading template file {}",fileName.replace("template_",""));
                readFile(getTemplateDir() + fileName.replace("template_",""));
            } else if(fileName.startsWith("log_")){
                logger.debug("Reading log file {}",fileName);
                readFile(getLoggingDir()+ fileName.replace("log_", ""));
            }
        } catch (IOException e) {
            logger.error("could not read file " + fileName, e);
        }
    }

    public String getCurrentFileName(){
        return currentFileName;
    }
    public String getCurrentFile(){
        return currentFileContent;
    }

    public void setProcessId(String probe) {
        processId = probe;
    }

    public String getProcessId() {
        return processId;
    }

    public boolean isRunning(){
        return !Strings.isNullOrEmpty(processId);

    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        PanaceaInstance that = (PanaceaInstance) o;

        if (directory != null ? !directory.equals(that.directory) : that.directory != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return directory != null ? directory.hashCode() : 0;
    }

    private void readFile(String file) throws IOException {
        logger.debug("Reading file {}", file);
        List<String> ss = Files.readLines(new File(file), Charset.forName("UTF-8"));
        StringBuilder buffer = new StringBuilder();
        for (String s : ss) {
            buffer.append('\n').append(s);
        }
        logger.debug("file content is {}", buffer.toString());
        currentFileContent = buffer.toString();
    }



}
